/////////////////////////////////////////////////////////////////////////////
// Purpose:     Concurrent light-weight processes management
// Author:      Jesus Gonzalez
// Modified by: 
// Copyright:   (c) 2003-2013 Jesus Gonzalez <jgonzalez@gdr-sistemas.com>
// License:     BSD License
/////////////////////////////////////////////////////////////////////////////

#ifndef THREAD_H_
#define THREAD_H_

/**
 * \file
 * Concurrent light-weight processes management.
 */

#include <SmartLib/SmartPtr.h>

///@defgroup proc_mgmt Process management
///@{

class ThreadPrvSys;

/**
 * The Thread abstract class represents a light-weight process (thread) that
 * can be executed concurrently to other threads inside a heavy-weight process.
 *
 * To implement a thread, define your own derived class implementing the
 * @ref EntryPoint() method.
 */
class Thread : public SmartObject
{
public:
    /**
     * Destructor.
     */
    virtual ~Thread();

    /**
     * Executes the thread.
     *
     * If \a detached is \p false, the thread is created as joinable, meaning
     * that another thread has to wait for this thread to finish and get the
     * its exit status by calling Wait().
     *
     * If \a detached is \p true, the thread is created as detached, meaning
     * that it's executed independently from other threads.
     *
     * @remark Joinable threads resources are not freed until another thread
     * waits for them, thus it's **mandatory** that another process successfully
     * calls Wait() at some time.
     *
     * @remark Detached threads resources are freed automatically when the
     * thread finishes (the EntryPoint() method returns), but other threads
     * can't wait for them to finish (calling Wait() will raise a runtime error),
     * and therefore their returned status code is lost.
     *
     * @param[in] detached If \p true, the thread is detached, otherwise it's joinable.
     * @throws RuntimeException When the thread is already running
     */
    void Run(bool detached = true);

    /**
     * Waits for a joinable thread to finish.
     *
     * @remark Calling this method on a detached thread will result in a runtime error.
     *
     * @param[out] exitStatus Status code returned by the thread
     * @param[in] noblock If \p true, the call won't block if the thread has not
     *                    finished yet, otherwise it will block until the thread
     *                    finishes.
     * @return \p True if successful (the thread has finished), \p false otherwise
     *         (the thread is still running)
     * @throws RuntimeError When the thread is not joinable
     */
    bool Wait(long &exitStatus, bool noblock = true);

    /**
     * This is the first method that is called when the thread is run.
     *
     * @return Status code
     */
    virtual long EntryPoint() = 0;

    /**
     * Checks if the thread is running.
     * @return \p True if the thread is running, \p false if it has finished
     */
    bool isRunning() const;

protected:
    /**
     * Default constructor, creates a new thread.
     *
     * The new thread is executed immediately if \a runNow is \p true. Otherwise
     * it is not executed yet, and it can be run by calling Run() at a later time.
     *
     * @see Run
     *
     * @param[in] runNow If \p true, the thread is executed immediately.
     * @param[in] detached If \p true, the thread is created as detached, otherwise
     *                     it's created as joinable
     *                     (ignored if \a runNow is \p false).
     */
    Thread(bool runNow, bool detached = true);

private:
    ThreadPrvSys* m_prvsys;

    friend class ThreadPrvSys;
};

///@}

#endif // THREAD_H_
